/*
 * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "esp_log.h"
#include "driver/ledc.h"
#include "lamp_ctrl.h"
#include "nvs_value.h"
#include "touch_board.h"
#include "h03_config.h"
#include "main.h"
#include "mqtt_cjson_handle.h"

#define TAG "[LAMP]"

#define MIN_LIGHT   96

lamp_t lamp;
lamp_t lamp_ex;

static uint16_t value_y_ex;
static uint16_t value_w_ex;


/*
 * This callback function will be called when fade operation has ended
 * Use callback only if you are aware it is being called inside an ISR
 * Otherwise, you can use a semaphore to unblock tasks
 */

// const uint16_t pwm[256] = {
// 	0, 90, 91, 93, 95, 97, 98, 100, 102, 104, 
// 	105, 107, 109, 111, 112, 114, 116, 118, 119, 121, 
// 	123, 125, 126, 128, 130, 132, 134, 136, 138, 141, 
// 	143, 145, 148, 150, 153, 155, 158, 161, 164, 167, 
// 	170, 173, 176, 179, 182, 186, 189, 193, 196, 200, 
// 	204, 208, 212, 216, 220, 224, 228, 233, 237, 242, 
// 	247, 251, 256, 261, 266, 271, 277, 282, 287, 293, 
// 	299, 304, 310, 316, 322, 328, 335, 341, 348, 354, 
// 	361, 368, 375, 382, 389, 396, 404, 411, 419, 427, 
// 	435, 443, 451, 459, 467, 476, 484, 493, 502, 511, 
// 	520, 530, 539, 548, 558, 568, 578, 588, 598, 609, 
// 	619, 630, 640, 651, 662, 674, 685, 696, 708, 720, 
// 	732, 744, 756, 769, 781, 794, 807, 820, 833, 846, 
// 	860, 873, 887, 901, 915, 929, 944, 958, 973, 988, 
// 	1003, 1018, 1034, 1050, 1065, 1081, 1097, 1114, 1130, 1147, 
// 	1164, 1181, 1198, 1215, 1233, 1250, 1268, 1286, 1305, 1323, 
// 	1342, 1361, 1380, 1399, 1418, 1438, 1458, 1478, 1498, 1518, 
// 	1539, 1559, 1580, 1601, 1623, 1644, 1666, 1688, 1710, 1732, 
// 	1755, 1778, 1801, 1824, 1847, 1871, 1895, 1919, 1943, 1967, 
// 	1992, 2017, 2042, 2067, 2093, 2118, 2144, 2170, 2197, 2223, 
// 	2250, 2277, 2305, 2332, 2360, 2388, 2416, 2444, 2473, 2502, 
// 	2531, 2560, 2590, 2620, 2650, 2680, 2711, 2741, 2772, 2804, 
// 	2835, 2867, 2899, 2931, 2963, 2996, 3029, 3062, 3096, 3129, 
// 	3163, 3197, 3232, 3267, 3302, 3337, 3372, 3408, 3444, 3480, 
// 	3517, 3553, 3590, 3628, 3665, 3703, 3741, 3780, 3818, 3857, 
// 	3896, 3936, 3975, 4015, 4055, 4095, 
// }; 

void lamp_set_value(ledc_channel_t channel, uint16_t brightness)
{
    // ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, channel, pwm[brightness]));
    ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, channel, brightness));
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, channel));
}

void lamp_set_brightness(uint8_t brightness, uint8_t colortemp)
{
    uint16_t value_y;
    uint16_t value_w;

    value_y = 255-colortemp;
    value_w = colortemp;
    if(value_y != 0){
        value_y = brightness * value_y / 255;
        value_y = value_y*4095/255;
    }
    if(value_w != 0){
        value_w = brightness * value_w / 255;
        value_w = value_w*4095/255;
    }
    lamp_set_value(LED_CHANNEL_Y, value_y);
    lamp_set_value(LED_CHANNEL_W, value_w);

    value_y_ex = value_y;
    value_w_ex = value_w;
} 

void lamp_set_fade(uint8_t brightness, uint8_t colortemp, uint16_t delay_ms)
{
    uint16_t value_y;
    uint16_t value_w;
    uint16_t value_yy = 0;
    uint16_t value_ww = 0;
    uint16_t delay_ms_p;
    uint8_t max_step;

    // printf("brtn:%d\n", brightness);
    if(brightness != 0 && brightness < 240){
        brightness += 16;
    }
    value_y = 255-colortemp;
    value_w = colortemp;
    value_y = brightness * value_y / 255;
    // value_y = pwm[value_y];
    value_y = value_y*4095/255;
    value_w = brightness * value_w / 255;
    // value_w = pwm[value_w];
    value_w = value_w*4095/255;

    uint16_t y = 0;
    uint16_t w = 0;
    if(delay_ms >= 500){
        max_step = 50;
    }else if(delay_ms >= 200){
        max_step = 20;
    }else{
        max_step = 5;
    }
    delay_ms_p = delay_ms/max_step;
    value_yy = value_y;
    value_ww = value_w;
    for (uint8_t i = 0; i < max_step; i++) {
        y = (value_yy - value_y_ex) * i / max_step;
        y += value_y_ex;
        w = (value_ww - value_w_ex) * i / max_step;
        w += value_w_ex;

        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LED_CHANNEL_Y, y));
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LED_CHANNEL_W, w));
        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LED_CHANNEL_Y));
        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LED_CHANNEL_W));
        vTaskDelay(delay_ms_p / portTICK_PERIOD_MS);
    }
    // if(value_y == 0){
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LED_CHANNEL_Y, value_y));
        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LED_CHANNEL_Y));
    // }
    // if(value_w == 0){
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LED_CHANNEL_W, value_w));
        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LED_CHANNEL_W));
    // }
    value_y_ex = value_y;
    value_w_ex = value_w;
}

static void lamp_open(void)
{
    ESP_LOGI(TAG, "lamp_open");
    cJSON_creat_attr("onoff_status", 1);

    indicator_updata();
    lamp_set_fade(lamp.brightness_val, lamp.color_temp, 500);
    event_flag.led_break = 1;
}

static void lamp_close(void)
{
    ESP_LOGI(TAG, "lamp_close");
    indicator_updata();
    cJSON_creat_attr("onoff_status", 0);
    lamp_set_fade(0, lamp.color_temp, 200);
    event_flag.led_break = 1;
}

static void lamp_change(uint8_t brightness, uint8_t colortemp, uint16_t delay_ms)
{
    ESP_LOGI(TAG, "lamp_change");
    indicator_updata();
    lamp_set_fade(brightness, colortemp, 200);
}

void lamp_updata(uint8_t onoff, uint8_t brightness, uint8_t colortemp)
{
    if(lamp_ex.onoff_status != onoff){
        lamp_ex.onoff_status = onoff;
        if(onoff == 1){
            lamp_open();
        }else{
            lamp_close();
        }
    }else{
        lamp_change(brightness, colortemp, 200);
    }
}

void lamp_manage_init(void)
{
    ESP_LOGI(TAG, "initialized LED Controller");

    ledc_timer_config_t ledc_timer = {
        .duty_resolution = LEDC_TIMER_BIT_NUM,
        .freq_hz = LEDC_BASE_FREQ,
        .speed_mode = LEDC_MODE,
        .timer_num = LEDC_TIMER_0
    };
    ledc_timer_config(&ledc_timer);

    ledc_channel_config_t ledc_channel1 = {
        .channel = LED_CHANNEL_Y,
        .duty = 0,
        .gpio_num = LED_GPIO_Y,
        .speed_mode = LEDC_MODE,
        .timer_sel = LEDC_TIMER_0,
        .flags.output_invert = LEDC_INTR_DISABLE
    };
    ledc_channel_config(&ledc_channel1);

    ledc_channel_config_t ledc_channel2 = {
        .channel = LED_CHANNEL_W,
        .duty = 0,
        .gpio_num = LED_GPIO_W,
        .speed_mode = LEDC_MODE,
        .timer_sel = LEDC_TIMER_0,
        .flags.output_invert = LEDC_INTR_DISABLE
    };
    ledc_channel_config(&ledc_channel2);

    if(device_attr.silent_ota == 0){
        lamp_set_brightness(0, lamp.color_temp);
    }else{
        if(lamp.onoff_status == 1){
            lamp_set_brightness(lamp.brightness_val, lamp.color_temp);
        }else{
            lamp_set_brightness(0, lamp.color_temp);
        }
    }
    ESP_LOGI(TAG, "LAMP brightness: %d", lamp.brightness_val);
}